package com.easylinkin.linkappapi.openapi.service.impl;

import cn.hutool.core.util.XmlUtil;
import com.baomidou.mybatisplus.extension.service.additional.query.impl.LambdaQueryChainWrapper;
import com.easylinkin.linkappapi.openapi.dto.RealTimeWeather;
import com.easylinkin.linkappapi.openapi.mapper.RealTimeWeatherMapper;
import com.easylinkin.linkappapi.openapi.service.WeatherTimingSynService;
import com.easylinkin.linkappapi.openapi.util.HttpClientUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.HttpGet;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.*;

/**
 * @program: linkapp-group-cloud
 * @description: 定时同步天气
 * @author: chenkaixuan
 * @create: 2021-10-11 15:22
 */
@Slf4j
@Service
public class WeatherTimingSynServiceImpl implements WeatherTimingSynService {
    @Resource
    private RedissonClient redisson;
    @Resource
    RealTimeWeatherMapper realTimeWeatherMapper;
    @Value("${linkapp.openReceiving:true}")
    private Boolean openReceiving;

    /***
     * 定时同步天气
     */
//    @Scheduled(fixedDelay = 1 * 30 * 60 * 1000)
    public boolean synchronizationWeather(){
        if (!openReceiving) {
            log.info("openReceiving 为false");
            return false;
        }
        RLock redissonLock = redisson.getLock("synchronizationWeather_lock");
        if (redissonLock.tryLock()) {
            try {
                //获取天气并保存
                getWeather(null);
            } catch (Exception e) {
                log.error("synchronizationWeather error:", e);
                e.printStackTrace();
                return false;
            } finally {
                redissonLock.unlock();
            }
        }
        return true;
    }

    @Override
    public List<RealTimeWeather> getRealTimeWeatherAll(RealTimeWeather realTimeWeather){
       return new LambdaQueryChainWrapper<>(realTimeWeatherMapper)
                .eq(!StringUtils.isEmpty(realTimeWeather.getCityCode()), RealTimeWeather::getCityCode,realTimeWeather.getCityCode())
                .ge(realTimeWeather.getQuertStartTime()!= null, RealTimeWeather::getCreatetime,realTimeWeather.getQuertStartTime())
                .le(realTimeWeather.getQuertEndTime()!= null, RealTimeWeather::getCreatetime,realTimeWeather.getQuertEndTime())
                .orderByDesc(RealTimeWeather::getCreatetime)
                .list();
    }


    private  void getWeather(String cityKey){
        if(StringUtils.isEmpty(cityKey)){
            //默认黄陂
            cityKey="101200103";
        }
        log.info("获取天气信息param cityKey："+cityKey);
        HttpGet httpGet = new HttpGet("http://wthrcdn.etouch.cn/WeatherApi?citykey="+cityKey);
        String str = HttpClientUtil.doGet(httpGet);
        log.info("获取天气信息result："+str);
        if(StringUtils.isEmpty(str)){
            return;
        }
        Map<String, Object> map = XmlUtil.xmlToMap(str);
        if(map == null || map.size()<=0){
            return;
        }
        RealTimeWeather realTimeWeather = initRealTimeWeather(map, cityKey);
        if(realTimeWeather == null){
            return;
        }
        realTimeWeatherMapper.insert(realTimeWeather);
    }

    private static RealTimeWeather initRealTimeWeather(Map<String, Object> map, String cityKey){
        RealTimeWeather realTimeWeather = initData(map);
        if(realTimeWeather == null){
            return null;
        }
        realTimeWeather.setId(UUID.randomUUID().toString().replaceAll("-", ""));
        realTimeWeather.setCityCode(cityKey);
        realTimeWeather.setCreatetime(LocalDateTime.now());
        HashMap forecast = (HashMap) map.get("forecast");
        if(forecast == null ||forecast.size()<=0){
            return realTimeWeather;
        }
        ArrayList weather = (ArrayList) forecast.get("weather");
        if(weather == null || weather.size()<=0){
            return realTimeWeather;
        }
        HashMap hashMap = (HashMap) weather.get(0);
        if(hashMap == null ||hashMap.size()<=0){
            return realTimeWeather;
        }
        realTimeWeather.setHigh(String.valueOf(hashMap.get("high")));
        realTimeWeather.setLow(String.valueOf(hashMap.get("low")));
        HashMap type = (HashMap) hashMap.get("night");
        if(type != null){
            realTimeWeather.setNightType(String.valueOf(type.get("type")));
        }
        type = (HashMap) hashMap.get("day");
        if(type != null){
            realTimeWeather.setDayType(String.valueOf(type.get("type")));
        }
        return realTimeWeather;
    }

    /***
     * 反射添加数据
     * @param collect
     * @return
     */
    private static RealTimeWeather initData(Map<String, Object> collect){
        RealTimeWeather data=new RealTimeWeather();
        Field[] declaredFields = data.getClass().getDeclaredFields();
        try {
            for (Field declaredField : declaredFields) {
                String propValue=String.valueOf(collect.get(declaredField.getName()));
                if(!StringUtils.isEmpty(propValue) && !"null".equals(propValue)){
                    PropertyDescriptor pd = new PropertyDescriptor(declaredField.getName(), data.getClass());
                    //获取set方法
                    Method method = pd.getWriteMethod();
                    //动态参数类型装换
                    Object value=paramTypeConvert(declaredField,propValue);
                    //赋值
                    method.invoke(data,value);
                }
            }
        } catch (IllegalAccessException | InvocationTargetException | IntrospectionException | NoSuchMethodException | ClassNotFoundException e) {
            log.error("查询实时天气反射set数据错误:{}",e.getMessage());
            throw new IllegalArgumentException(e.getMessage());
        }
        return data;
    }

    /***
     * 参数类型动态转换
     * @param field
     * @param value
     * @return
     * @throws ClassNotFoundException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    private static Object paramTypeConvert(Field field, String value) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        //field为反射出来的字段类型
        String ftype = field.getType().getName();
        String fstype = field.getType().getSimpleName();
        if (field.getType() == String.class)
        {
            return value;
        }
        else if (ftype.indexOf("java.lang.") == 0) {
            // java.lang下面类型通用转换函数
            Class<?> class1 = Class.forName(ftype);
            Method method = class1.getMethod("parse" + parseParam(fstype),String.class);
            if (method != null) {
                Object ret = method.invoke(null, value);
                if (ret != null)
                {
                    return ret;
                }
            }
        }
        return value;
    }

    private static Object parseParam(String fstype){
        switch (fstype)
        {
            case "Integer":
                return "Int";
        }
        return fstype;
    }
}
